package robber.impl;

import configuration.RobConfiguration;
import http.util.ArrayUtil;
import http.util.HtmlUtil;
import http.util.ParseUtil;
import main.robClass;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.internal.StringUtil;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import robber.AbstractRobber;
import timer.saveCookieManager;
import timer.saveCoursesManager;
import timer.saveRobberManager;
import user.IUser;
import user.impl.robUser.RobUser;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

import static java.lang.Thread.sleep;


/**
 * 抢公选课类
 * AbstractRobber定义了抢课用户类的一些行为与方法
 * 在CommonRobber类中进行特性化处理
 * 将AbstractRobber类的职责转移为抢公选课的职责
 ***/

/**
 * CommonRoober职责
 * Common课程抢课思路（初级）:
 * login获取cookie
 * 此时login页面的route 有三种
 * route=c2337810a5bcaf2ec197c551cceae905; route=a79c11333bcfcab69beab260e38ff9cb; route=2fb3815e28a93711a595e0fe7ad90e73;
 * route的不同将决定了你的抢课提交按钮返回是否有信息
 * 专科这边好像还能把提交按钮隐藏 暂时不清楚是不是route控制的网页
 * 总之route不同 访问的网页也不同 route可以作为一个状态来提交给服务端 服务端判别后决定是否返回抢课状态
 * 目前猜测 抢课之前的几天 2fb3815e28a93711a595e0fe7ad90e73 是可以有状态的 其他两个逐渐开放 因此保险起见 要做两套route处理规则
 * 一种route处理规则为单独2fb3815e28a93711a595e0fe7ad90e73 这样非常高效率 但有可能抢课那天这个route用不到
 * 另一种是所有route都用 代价是发包有可能是失败的 低效率的 但抢课那天总有能发包成功route
 * <p>
 * 猜测 route与第一个viewstate有关(登陆页面的) 但第一个viewstate好像无关于发包成功的状态
 * route是决定了后续的viewstate获取 只有viewstate获取正确才能发包正常 才有返回信息
 * <p>
 * 当我们拿到route后 还有一个asp.net的cookie 那个是用户cookie
 * 当我们login后 route + user cookie将决定其两者可用状态 以后发包都要携带他们去访问数据
 * route+user先访问/xs_main.aspx?xh=1908010101
 * 目的是获取viewstate
 * 将/xs_main.aspx?xh=1908010101的viewstate访问http://192.168.170.253/xf_xsqxxxk.aspx?xh=1908010101&xm=%CB%D5%B3%AC%CF%CD&gnmkdm=N121203
 * 就能拿到真正的发包viewstate
 * 后续post viewstate到/xf_xsqxxxk.aspx就可以了 也要带上相关post body即可
 * <p>
 * 现在需要测试的是 多cookie下是否可行
 * 为了方便测试我将过滤掉非route=2fb3815e28a93711a595e0fe7ad90e73;的cookie
 */
public class CommonRobber extends AbstractRobber {


    /**CommonRobber抢课参数*/
    /**由firstViewState获取的CommonCourseViewState*/
    /**实际上都藏在html 用ViewStateFromHtml方法都可获取以上两种viewState*/
    /**
     * 只不过是公选课抢课要第二个（SecondViewState）罢了
     */

    /**
     * 发包时候需要的Cookie与发包firstViewState绑定 需要缓存到数据库
     * 到时候获取postViewState直接调用这里就行
     * 如果软件崩溃重启则调用里面的cookie执行预初始化过程
     */
    HashMap<String, String> cookieAndFirstViewState = new HashMap<String, String>();

    /**
     * 发包时候需要的Cookie与发包ViewState绑定 需要缓存到数据库
     * 到时候发包直接调用这里就行
     * 如果软件崩溃重启则调用里面的cookie执行预初始化过程
     */
    HashMap<String, String> cookieAndPostViewState = new HashMap<String, String>();

    public HashMap<String, String> getRandomCookieAndFirstViewState() {
//        System.out.println("getRandomCookieAndFirstViewState()");
//        System.out.println(getCookieAndFirstViewState());
        return ArrayUtil.getRandomDataFromHashMap(getCookieAndFirstViewState());
    }

    public HashMap<String, String> getRandomCookieAndPostViewState() {
//        System.out.println("getRandomCookieAndPostViewState()");
//        System.out.println(getCookieAndPostViewState());
        return (HashMap<String, String>) ArrayUtil.getRandomDataFromHashMap(getCookieAndPostViewState());
    }

    public void addCookieAndFirstViewState(String cookie, String firstViewState) {
        if (StringUtils.isBlank(firstViewState)) {
            return;
        }
        cookieAndFirstViewState.put(cookie, firstViewState);
    }

    public HashMap<String, String> getCookieAndFirstViewState() {
        return cookieAndFirstViewState;
    }

    public void setCookieAndFirstViewState(HashMap<String, String> cookieAndFirstViewState) {
        this.cookieAndFirstViewState = cookieAndFirstViewState;
    }


    public void addCookieAndPostViewState(String cookie, String postViewState) {
        if (StringUtils.isBlank(postViewState)) {
            return;
        }
        cookieAndPostViewState.put(cookie, postViewState);
    }

    public HashMap<String, String> getCookieAndPostViewState() {
        return cookieAndPostViewState;
    }

    public void setCookieAndPostViewState(HashMap<String, String> cookieAndPostViewState) {
        this.cookieAndPostViewState = cookieAndPostViewState;
    }

    /**
     * 等待删除
     */
    String postViewState;

    public String getPostViewState() {
        return postViewState;
    }

    public void setPostViewState(String postViewState) {
        if (StringUtils.isBlank(postViewState)) {
            return;
        }
        this.postViewState = postViewState;
    }


    public CommonRobber(IUser user) {
        super(user);
    }

    /**
     * 同步搜索课程表 并显示 - 一般用来搜索设置课表
     */
    @Override
    synchronized
    protected HashMap<String, String> sync_search_Classes() {
        try {
            String randomCookie = getUser().getRandomCookie();
            if (StringUtils.isBlank(randomCookie)) {
                return saveCoursesManager.getGlobalIdAndCourseNameCache();
            }
            Response response = getBasicRequest().common_sync_getWithRandomCookie(getUser(), randomCookie);
            if (response == null) {
                robClass.logger.info("搜索公选课程失败 可能随机random");
                return saveCoursesManager.getGlobalIdAndCourseNameCache();
            }

            String responseHtml = response.body().string();
//            response.close();
            Request request_main = getBasicRequest().getBasicRequest().newBuilder()
                    .addHeader("cookie", randomCookie)
//                    .addHeader("cache-control", "no-cache")
//                    .addHeader("pragma", "no-cache")
                    .addHeader("Upgrade-Insecure-Requests", "1")
                    .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36")
                    .url(RobConfiguration.URL + "/xs_main.aspx?xh=" + getUser().getUsername())
                    .get()
                    .build();
            Call call_main = getBasicRequest().getDefaultHttpClient().newCall(request_main);
            call_main.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {}
                @Override
                public void onResponse(Call call, Response response) {
                    response.close();
                    /**获取到firstViewState*/
                    String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
                    if (firstViewState != null && !StringUtils.isBlank(firstViewState)) {
                        addCookieAndFirstViewState(randomCookie, firstViewState); //应该数据库保存一波Robber

                        /**二次发包*/
                        System.out.println("二次发包");
                        try {
                            String bodyContent = "&__EVENTTARGET=dpkcmcGrid%3AtxtPageSize&__EVENTARGUMENT=&ddl_kcxz=&ddl_ywyl=%D3%D0&ddl_kcgs=&ddl_xqbs=1&ddl_sksj=&TextBox1=&Button2=%C8%B7%B6%A8&dpkcmcGrid%3AtxtChoosePage=1&dpkcmcGrid%3AtxtPageSize=150";
                            String uri = "/xf_xsqxxxk.aspx?xh=" + getUser().getUsername() + "&xm=" + URLEncoder.encode(getUser().getStudentName(), "gb2312") + "&gnmkdm=N121203";
                            try {
                                String out = "__VIEWSTATE=" +
                                        URLEncoder.encode(firstViewState, "gb2312") +
                                        bodyContent;
                                Request request = getBasicRequest().getBasicRequest().newBuilder()
                                        .addHeader("referer", RobConfiguration.URL + "/xf_xsqxxxk.aspx?xh=" + getUser().getUsername() + "&xm=" + URLEncoder.encode(getUser().getStudentName(), "gb2312") + "&gnmkdm=N121203")
                                        .addHeader("cookie", randomCookie)
//                        .addHeader("cache-control", "no-cache")
//                        .addHeader("pragma", "no-cache")
                                        .url(RobConfiguration.URL + uri)
                                        .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=gb2312"), out))
                                        .build();

                                Call call2 = getBasicRequest().getPreInitClient().newCall(request);
                                call2.enqueue(new Callback() {
                                    @Override
                                    public void onFailure(Call call, IOException e) {
                                    }

                                    @Override
                                    public void onResponse(Call call, Response response) throws IOException {
                                        String res = response.body().string();
                                        System.out.println(res);
                                        response.close();
                                        System.out.println("二次发包-接收");
                                        /**解析课表*/
                                        HtmlUtil.parseCommonSelectCourseList(res, CommonRobber.super.getIdAndCourseNameCache(), true);
                                        String postViewState = HtmlUtil.getViewStateFromResponseHtml(res);
                                        /**过滤没用的viewstate*/
                                        if (!StringUtil.isBlank(postViewState) && postViewState.length() > 10000) {
                                            addCookieAndPostViewState(randomCookie, postViewState);
                                            saveCookieManager.updateUserToGlobalIdAndCookies(getUser());
                                            saveRobberManager.updateUserToGlobalIdAndRobberInfo(CommonRobber.this);
                                        }
                                    }
                                });
                            } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                            }


                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    saveCookieManager.updateUserToGlobalIdAndCookies(CommonRobber.super.getUser());
                    saveRobberManager.updateUserToGlobalIdAndRobberInfo(CommonRobber.this);
                }
            });

        } catch (Exception e) {
            robClass.logger.info(getUser().getUsername() + "#搜索课程失败");
            return saveCoursesManager.getGlobalIdAndCourseNameCache();
        }


        return super.getIdAndCourseNameCache();

    }
//    synchronized
//    protected HashMap<String, String> sync_search_Classes() {
//        Response response = null;
//        String responseHtml = null;
//        try {
//            String randomCookie = getUser().getRandomCookie();
//            response = getBasicRequest().common_sync_getWithRandomCookie("/xf_xsqxxxk.aspx?xh=" + super.getUser().getUsername() + "&xm=" + URLEncoder.encode(super.getUser().getStudentName(), "gb2312") + "&gnmkdm=N121203", this.getUser());
//            if (response == null) {
//                robClass.logger.info("搜索公选课程失败 可能随机random");
//                return saveCoursesManager.getGlobalIdAndCourseNameCache();
//            }
//            responseHtml = response.body().string();
////            System.out.println(responseHtml);
//            HtmlUtil.parseCommonSelectCourseList(responseHtml, super.getIdAndCourseNameCache(), true);
//            //robClass.logger.info("资源初始化后的课表数据: " + super.getIdAndCourseNameCache());
//
//            String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
//            //super.getFirstViewState().add(firstViewState);
////            addCookieAndFirstViewState(randomCookie, firstViewState);
//            saveCookieManager.updateUserToGlobalIdAndCookies(CommonRobber.super.getUser());
//            saveRobberManager.updateUserToGlobalIdAndRobberInfo(CommonRobber.this);
//        } catch (Exception e) {
//            robClass.logger.info("同步搜索过程出现异常,使用缓存课表#" + saveCoursesManager.getGlobalIdAndCourseNameCache().size());
//            return saveCoursesManager.getGlobalIdAndCourseNameCache();
//        }
//        if (super.getIdAndCourseNameCache() == null || super.getIdAndCourseNameCache().isEmpty()) {
//            return saveCoursesManager.getGlobalIdAndCourseNameCache();
//        }
//        //获取公选课课表的时候设置公选课需要的前置viewState
////        String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
////        super.getFirstViewState().add(firstViewState);
//        return super.getIdAndCourseNameCache();
//        /**1.返回的是目前修改后的
//         * 2.先于缓存中的*/
//    }

    /**
     * 异步获取课程表 - 一般用来初始化前置资源
     * 同时获取firstViewState -> 决定了公选课一个必备参数 commonViewState
     */
    @Override
    protected void async_search_Classes() {
        try {
            String randomCookie = getUser().getRandomCookie();
            if (StringUtils.isBlank(randomCookie)) {
                return;
            }
            /**随机获取Cookie去Xsqxxxk页面获取第一个viewstate 并且获取且存储公选课信息*/
            //System.out.println("async_search_Classes随机:" + randomCookie);
            Request request_main = getBasicRequest().getBasicRequest().newBuilder()
                    .addHeader("cookie", randomCookie)
                    .addHeader("cache-control", "no-cache")
                    .addHeader("pragma", "no-cache")
                    .addHeader("Upgrade-Insecure-Requests", "1")
                    .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36")
                    .url(RobConfiguration.URL + "/xs_main.aspx?xh=" + getUser().getUsername())
                    .get()
                    .build();
            Call call_main = getBasicRequest().getDefaultHttpClient().newCall(request_main);
            call_main.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {}
                @Override
                public void onResponse(Call call, Response response) {
                    response.close();
                }
            });
            Call call = getBasicRequest().common_async_getXsqxxxkViewStateWithCookie(getUser(), randomCookie);
            if (call == null) {
                return;
            }
            call.enqueue(new Callback() {
                /**网络获取失败 - 使用本地公选课表缓存*/
                @Override
                public void onFailure(Call call, IOException e) {
                    robClass.logger.info("异步-获取公选课表失败: 网络请求超时");
                    if (CommonRobber.super.getIdAndCourseNameCache().isEmpty()) {
                        robClass.logger.info("异步-获取公选课表失败, 由于用户课表为空, 使用缓存课表#" + saveCoursesManager.getGlobalIdAndCourseNameCache().size());
                        CommonRobber.super.setIdAndCourseNameCache(saveCoursesManager.getGlobalIdAndCourseNameCache());
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String responseHtml = response.body().string();
//                    System.out.println("异步获取课程结果" + responseHtml);
                    response.close();
                    /**解析课表*/
                    HtmlUtil.parseCommonSelectCourseList(responseHtml, CommonRobber.super.getIdAndCourseNameCache(), false);
                    /**获取到firstViewState*/
                    String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
                    if (firstViewState == null) {
                        return;
                    }
                    //System.out.println("async_search_Classes成功随机:" + randomCookie + ":" + firstViewState);
                    if (!StringUtils.isBlank(firstViewState) && firstViewState.length() > 10000) {
                        addCookieAndFirstViewState(randomCookie, firstViewState); //应该数据库保存一波Robber
                        //System.out.println("addCookieAndFirstViewState");
                    } else {
                        System.out.println("出问题的FVS" + firstViewState);
                        return;
                    }
                    /**
                     * 优化思路
                     * 第一个viewState获取后 缓存下来
                     * 获取第二个viewState 缓存下来
                     * 再根据第二个viewState不断发包*/
//                    String postViewState = getBasicRequest().getCommonViewState("/xf_xsqxxxk.aspx?xh=" + getUser().getUsername() + "&xm=" + URLEncoder.encode(getUser().getStudentName(), "gb2312") + "&gnmkdm=N121203",
//                            getUser(), getUser().getRandomCookie());
//                    if (!StringUtil.isBlank(postViewState)) {
//                        setPostViewState(postViewState);
//                        System.out.println("设置Fvs");
//                        /**获取FirstViewState后进行序列化备份*/
                    saveCookieManager.updateUserToGlobalIdAndCookies(CommonRobber.super.getUser());
                    saveRobberManager.updateUserToGlobalIdAndRobberInfo(CommonRobber.this);
//                    }


                }
            });
        } catch (Exception e) {
            robClass.logger.info(getUser().getUsername() + "#搜索课程失败");
        }
    }

    @Override
    protected void stop_rob() {

    }

    @Override
    protected void setTimer_rob() {

    }


    /**
     * 抢公选课功能 - 正常模式
     * 公选课有两个viewstate
     * 旧的viewstate为loginViewState/firstViewState
     * 新的为commonViewState
     **/
    /**
     * 抢课逻辑
     */
    public void rob(String classId, boolean isCrazyMode) {
        IUser user = getUser();
        HashMap<String, String> cookieAndPostViewState = getRandomCookieAndPostViewState();
        if (cookieAndPostViewState == null || cookieAndPostViewState.size() == 0) {
            return;
        }
        String randomCookie = user.getRandomCookie();
        if (StringUtils.isBlank(randomCookie)) {
            return;
        }
        String postViewState = cookieAndPostViewState.get(randomCookie);
        if (StringUtils.isBlank(postViewState)) {
            return;
        }
        try {
            String bodyContent = "&ddl_kcxz=&ddl_ywyl=%D3%D0&ddl_kcgs=&ddl_xqbs=1&ddl_sksj=&TextBox1=";
            StringBuilder sb = new StringBuilder(bodyContent);
            for (int i = 2; i <= 42; i++) {
                boolean select = false;
                for (String courseId : ((RobUser) (getUser())).getRobClasses()) {
                    if (saveCoursesManager.getGlobalIdAndCourseNameCache().isEmpty()) {
//                        System.out.println("saveCoursesManager.getGlobalIdAndCourseNameCache() 为空");
                        return;
                    }
                    Integer num2 = Integer.valueOf(saveCoursesManager.getGlobalIdAndCourseNameCache().get(courseId).split(":")[1].split(":")[0].split("ctl")[1]);
                    if (i == num2) {
                        sb.append("&" + URLEncoder.encode(saveCoursesManager.getGlobalIdAndCourseNameCache().get(courseId), "gb2312") + "=on");
                        select = true;
                        break;
                    }
                }
                if (!select) {
                    sb.append("&kcmcGrid%3A_ctl" + i + "%3Ajcnr=%7C%7C%7C");
                }
            }
            bodyContent = sb.toString() + "&dpkcmcGrid%3AtxtChoosePage=1&dpkcmcGrid%3AtxtPageSize=150&Button1=++%CC%E1%BD%BB++";
            String uri = "/xf_xsqxxxk.aspx?xh=" + user.getUsername() + "&xm=" + URLEncoder.encode(user.getStudentName(), "gb2312") + "&gnmkdm=N121203";
            Call call;

            /**狂暴模式发包*/
            if (RobConfiguration.isCrazyRobMode && isCrazyMode) {
                call = super.getBasicRequest().crazy_common_postWithCookieAndViewState(uri,
                        bodyContent,
                        randomCookie,
                        postViewState);
            } else {
                call = super.getBasicRequest().common_postWithCookieAndViewState(uri,
                        bodyContent,
                        randomCookie,
                        postViewState);
            }

            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    if (!RobConfiguration.isCrazyRobMode) {
                        robClass.logger.info(new Date() + "#" + getUser().getUsername() + " #异步-抢课失败: 网络请求超时");
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        if (getIdAndCourseNameCache().isEmpty()) {
                            setIdAndCourseNameCache(saveCoursesManager.getGlobalIdAndCourseNameCache());
                            robClass.logger.info("用户没有课表,目前从缓存中获取课表" + getIdAndCourseNameCache().size() + "#" + getIdAndCourseNameCache().toString());
                        }
                        String responseHtml = response.body().string();
                        response.close();
                        String courseName = classId;
                        if (getIdAndCourseNameCache().containsKey(classId)) {
                            courseName = getIdAndCourseNameCache().get(courseName);
                        }
                        /**解析抢课返回信息*/
                        if (responseHtml != null) {
//                            setPostViewState(HtmlUtil.getViewStateFromResponseHtml(responseHtml));
                            addCookieAndPostViewState(randomCookie, postViewState);
                            /**尝新测试性功能 我怀疑postViewState都是一样的*/
                            getCookieAndPostViewState().keySet().stream().forEach(key -> {
                                getCookieAndPostViewState().put(key, postViewState);
                            });
                            String ret_reason = ParseUtil.parseCommonRobScript(responseHtml);
                            System.out.println(user.getStudentName() + " " + courseName + " : " + ret_reason + ":" + "当前抢课cookie:" + randomCookie);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        robClass.logger.info("classId" + classId);
                        robClass.logger.info("IdAndCourseNameCache:" + getIdAndCourseNameCache().size());
                        robClass.logger.info("IdAndCourseNameCache:" + getIdAndCourseNameCache());
                        robClass.logger.info("找不到课程名字对应的内容");
                    }
                }
            });

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }


    /**
     * preRob()->login->cookie||->asyncSearchClasses()->get/set->firstViewState->isEmptyCookieAndFirstViewState
     */
    @Override
    protected void initPreRob(String courseId) {

        try {
            getBasicRequest().common_async_getXsqxxxkPostViewStateWithCookie(this);
        } catch (NullPointerException e) {
            robClass.logger.info("initPreRob - Null");
            e.printStackTrace();

        } catch (Exception e) {
            robClass.logger.info("initPreRob - Unknown");
            e.printStackTrace();
        }

    }


}

